//重新声明命名空间？
//类似objective-c中的？类是在别的地方定义的，在这只是要使用，直接声明一个同样名字的类？
AutodeskNamespace("Autodesk.ADN.Viewing.Extension");

var annotation = function(viewer){

    var ModeEnum = {
        kModeIddle: 0,
        kModeInitDrag: 1,
        kModeDrag: 2
    };

    const panelW = 400;
    const panelH = 600;

    var _mode = ModeEnum.kModeIddle;

    var _selectedMarkUpId = null;

    var _currentMarkUp = null;

    var _propComboId = null;

    var _markUps = {};

    var _self = this;

    var _propName = '';

    // var _htmlContent = '';

    //add by cz begin
    /*
        [function]  addMarker <function>    : add a new marker to viewer
        [parameter] data      <json>        : 
            .dbId   : dbId...
            .fragId : fragId...
            .content: html content.
            .attachmentPoint : 3d point, in the viewer.
            .textPos: 2d point, on the screen.
    */
    _self.addMarker = function(data){
        //new a markup
        let makeUp = newMarkUp(data.dbId, data.fragId, data.attachmentPoint);
        // makeUp.attachmentPoint = data.attachmentPoint;
        // makeUp.textPos = data.textPos;
        makeUp.divId = guid();
        // $('#' + _currentMarkUp.divId).html(data.content);
        //enable drag event
        // $('#dragTitle').mousedown(function(){
        //      $(viewer.container).bind('mousemove', _self.onMouseMove);    
        // });        
        // $('#dragTitle').mouseup(function(){
        //      $(viewer.container).unbind('mousemove', _self.onMouseMove);
        // })

        // $('#' + _currentMarkUp.divId).css({'visibility': 'visible'});
        _markUps[makeUp.divId] = makeUp;

        viewer.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, _self.onCameraChanged);

        _self.updateMarkUps();

        // _self.setDetailViewVisibility(false);
        // $('#overlayDivId').css('pointer-events', 'auto');
    }

    /*
        [function]  enableEdit  <function> : change the edit made
    */
    _self.enableEdit = function(){
        $(viewer.container). bind("click", _self.onMouseClick);
        viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, _self.onItemSelected);
        // viewer.setPropertyPanel(null);
    }

    _self.disableEdit = function(){
        $(viewer.container).unbind("click", _self.onMouseClick);
        viewer.removeEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, _self.onItemSelected);
        //console.log(_markUps);
    }

    _self.getMarkerData = function(){
        return {
            dbId : _currentMarkUp.dbId,
            fragId : _currentMarkUp.fragId,
            divId : _currentMarkUp.divId,
            attachmentPoint : _currentMarkUp.attachmentPoint,
        };
    }



    _self.clear = function(){        
        // _markUps = {};
        for(var i in _markUps){
            deleteMarkUp(_markUps[i]);
        }
        // updateMarkUps();
        _self.updateMarkUps();
    }

    /*
        [function]  putData     <function>: put data into the form
        [parameter] data        <object/json>: data that display
        [P.S.]  The id of html dom and the key of data should be the same, so it matchs by jquery
    */
    // _self.putData = function (data) {
    //     for(var k in data){
    //         $('.table').find('#' + k).val(data[k]);
    //     }
    // }

    /*
        [function]  setDetailViewVisibility : temp fuc to show or hide detail view
        [parameter] isVisible   <boolean>   : ...
    */
    // _self.setDetailViewVisibility = function(isVisible){
    //     var pathv = isVisible ? '1' : '0';
    //     var detailv = isVisible ? 'visible' : 'hidden';
    //     $('path').attr({'opacity': pathv});
    //     $('path').css({'opacity': pathv});
    //     $('#' + _currentMarkUp.divId).css({'visibility': detailv});
    //     _currentMarkUp.isVisible = isVisible;
    // }
    //edit by cz end

    ///////////////////////////////////////////////////////////////////////////
    // load callback
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.load = function (htmlContent) {
        // _htmlContent = htmlContent;
        function activateAnnotate() {

            // $(viewer.container).bind("click", _self.onMouseClick);

            // viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, _self.onItemSelected);

            viewer.setPropertyPanel(null);
        }

        // context menu stuff

        Autodesk.ADN.Viewing.Extension.MarkUpContextMenu = function (viewer) {
            Autodesk.Viewing.Extensions.ViewerObjectContextMenu.call(this, viewer);
        };

        Autodesk.ADN.Viewing.Extension.MarkUpContextMenu.prototype = Object.create(Autodesk.Viewing.Extensions.ViewerObjectContextMenu.prototype);

        Autodesk.ADN.Viewing.Extension.MarkUpContextMenu.prototype.constructor = Autodesk.ADN.Viewing.Extension.MarkUpContextMenu;

        // _self.viewer.setContextMenu(new Autodesk.ADN.Viewing.Extension.MarkUpContextMenu(_self.viewer));

        viewer.addEventListener(Autodesk.Viewing.EXPLODE_CHANGE_EVENT,_self.onExplode);

        _self.createOverlay(function(overlay) {
            _self.overlay = overlay;
        });

        activateAnnotate();

        //console.log("Autodesk.ADN.Viewing.Extension.Annotation loaded");
        // });

        return true;
    };

    _self.unload = function () {

        $(viewer.container).unbind("click", _self.onMouseClick);

        viewer.removeEventListener(
          Autodesk.Viewing.SELECTION_CHANGED_EVENT,_self.onItemSelected);

        // keep custom context menu loaded for delete annotation
        //viewer.setContextMenu(
        //  new Autodesk.Viewing.Extensions.ViewerObjectContextMenu(viewer));

        var panel = new Autodesk.Viewing.Extensions.ViewerPropertyPanel(
            viewer);

        viewer.setPropertyPanel(panel);

        $('#' +  _propComboId).remove();

        console.log("Annotation unloaded");

        return true;
    };

    ///////////////////////////////////////////////////////////////////////////
    // creates new markup
    //
    ///////////////////////////////////////////////////////////////////////////
    function newMarkUp(dbId, fragId, attachmentPoint) {

        var divId = guid();
       
        //小红原点，点击物体的时候出现的
        //Raphaël js
        //Raphaël is a small JavaScript library that should simplify your work with vector graphics on the web 
        var connector = _self.overlay.circle(
            0, 0, 10.0);
        connector.attr("stroke", "#2D74F6");
        connector.attr("fill", "#2D74F6");
        connector.click(function(){
            if(clickFunction){
                clickFunction();                
            }else{
                _self.setDetailViewVisibility(!_currentMarkUp.isVisible);
            }
        })


        var markUp = {
            dbId: dbId,
            fragId: fragId,
            // line: path,
            divId: divId,
            // textPos: null,
            connector: connector,
            attachmentPoint: attachmentPoint,
            position: _self.getMeshPosition(fragId)
        };     
        return markUp;
    }

    ///////////////////////////////////////////////////////////////////////////
    // delete a markUp
    //
    ///////////////////////////////////////////////////////////////////////////
    function deleteMarkUp(markUp) {

        $('#' + markUp.divId).remove();

        markUp.connector.remove();

        delete _markUps[markUp.divId];
    }

    ///////////////////////////////////////////////////////////////////////////
    // item selected callback
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.onItemSelected = function (event) {
        //console.log(event);
        if(event.dbIdArray.length) {

            //viewer.select([]);

            var dbId = event.dbIdArray[0];

            var fragId = event.fragIdsArray[0];

            switch (_mode) {

                case ModeEnum.kModeIddle:

                    _mode = ModeEnum.kModeInitDrag;

                    if (Array.isArray(fragId))
                        fragId = fragId[0];

                    _currentMarkUp = newMarkUp(dbId, fragId);

                    _markUps[_currentMarkUp.divId] = _currentMarkUp;
                    

                default:
                    break;
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // mouse click callback
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.onMouseClick = function(event) {
        //console.log(2);

        var screenPoint = {
            x: event.clientX,
            y: event.clientY
        };

        switch (_mode) {

            case ModeEnum.kModeInitDrag:

                var n = _self.normalizeCoords(screenPoint);

                var hitPoint = viewer.utilities.getHitPoint(
                    n.x,
                    n.y);

                if (hitPoint) {

                    var markUp = _currentMarkUp;

                    markUp.attachmentPoint = hitPoint;                    

                    markUp.textPos = screenPoint;                      

                    _self.updateMarkUp(markUp);

                    viewer.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, _self.onCameraChanged);

                    // _mode = ModeEnum.kModeDrag;

                    _markUps[_currentMarkUp.divId] = _currentMarkUp;

                    // _self.disableEdit();
                }

                break;

            // case ModeEnum.kModeDrag:

            //     _mode = ModeEnum.kModeIddle;

            //     _markUps[_currentMarkUp.divId] = _currentMarkUp;          
        
            //     _self.enableEdit(false);

            default: break;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // normalize screen coordinates
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.normalizeCoords = function(screenPoint) {

        var viewport =
            viewer.navigation.getScreenViewport();

        var n = {
            x: (screenPoint.x - viewport.left) / viewport.width,
            y: (screenPoint.y - viewport.top) / viewport.height
        };

        return n;
    }

    ///////////////////////////////////////////////////////////////////////////
    // mouse move callback
    ///////////////////////////////////////////////////////////////////////////
    _self.onMouseMove = function(event) {

        var screenPoint = {
            x: event.clientX,
            y: event.clientY
        };

        var markUp = _currentMarkUp;
        // console.log(markUp);

        markUp.textPos = screenPoint;

        _self.updateMarkUp(markUp);
    }

    ///////////////////////////////////////////////////////////////////////////
    // world -> screen coords conversion
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.worldToScreen = function(worldPoint, camera) {

        var p = new THREE.Vector4();

        p.x = worldPoint.x;
        p.y = worldPoint.y;
        p.z = worldPoint.z;
        p.w = 1;

        p.applyMatrix4(camera.matrixWorldInverse);
        p.applyMatrix4(camera.projectionMatrix);

        // Don't want to mirror values with negative z (behind camera)
        // if camera is inside the bounding box,
        // better to throw markers to the screen sides.
        if (p.w > 0)
        {
            p.x /= p.w;
            p.y /= p.w;
            p.z /= p.w;
        }

        // This one is multiplying by width/2 and â€“height/2,
        // and offsetting by canvas location
        var point = viewer.impl.viewportToClient(p.x, p.y);

        // snap to the center of the pixel
        point.x = Math.floor(point.x) + 0.5;
        point.y = Math.floor(point.y) + 0.5;

        return point;
    }

    ///////////////////////////////////////////////////////////////////////////
    // screen to world coordinates conversion
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.screenToWorld = function(event) {

        var screenPoint = {
            x: event.clientX,
            y: event.clientY
        };

        var viewport =
            viewer.navigation.getScreenViewport();

        var n = {
            x: (screenPoint.x - viewport.left) / viewport.width,
            y: (screenPoint.y - viewport.top) / viewport.height
        };

        return viewer.navigation.getWorldPoint(n.x, n.y);
    }

    ///////////////////////////////////////////////////////////////////////////
    // camera changed callback
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.onCameraChanged = function(event) {
        // console.log(_markUps);
        _self.updateMarkUps();
    };

    ///////////////////////////////////////////////////////////////////////////
    // explode changed callback
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.onExplode = function(event) {

        _self.updateMarkUps();
    };

    ///////////////////////////////////////////////////////////////////////////
    // update markUp graphics
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.updateMarkUp = function(markUp) {

        var pos = _self.getMeshPosition(markUp.fragId);

        var translation = {
            x: pos.x - markUp.position.x,
            y: pos.y - markUp.position.y,
            z: pos.z - markUp.position.z
        }

        var attachmentPoint = {
            x: markUp.attachmentPoint.x + translation.x,
            y: markUp.attachmentPoint.y + translation.y,
            z: markUp.attachmentPoint.z + translation.z
        }

        var screenPoint = _self.worldToScreen(attachmentPoint, viewer.getCamera());

        markUp.screenPoint = screenPoint;

        markUp.connector.attr({
            cx: screenPoint.x,
            cy: screenPoint.y
        });
    };

    _self.updateMarkUps = function() {
        for(var key in _markUps){
            _self.updateMarkUp(_markUps[key]);
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // create overlay 2d canvas                                              //
    ///////////////////////////////////////////////////////////////////////////
    _self.createOverlay = function (callback) {

        if (typeof Raphael === 'undefined') {
            callback(null);
        }

        var overlayDiv = document.createElement("div");

        overlayDiv.id = 'overlayDivId';

        viewer.container.appendChild(
            overlayDiv);

        overlayDiv.style.top = "0";
        overlayDiv.style.left = "0";
        overlayDiv.style.right = "0";
        overlayDiv.style.bottom = "0";
        overlayDiv.style.position = "absolute";
        overlayDiv.style.pointerEvents = "none";

        var overlay = new Raphael(
            overlayDiv,
            overlayDiv.clientWidth,
            overlayDiv.clientHeight);

        callback(overlay);
    }

    ///////////////////////////////////////////////////////////////////////////
    // get mesh postion
    //
    ///////////////////////////////////////////////////////////////////////////
    _self.getMeshPosition = function(fragId) {

        var mesh = viewer.impl.getRenderProxy(
          viewer.model,
          fragId);

        var pos = new THREE.Vector3();

        pos.setFromMatrixPosition(mesh.matrixWorld);

        return pos;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Generate GUID
    //
    ///////////////////////////////////////////////////////////////////////////
    function guid() {

        var d = new Date().getTime();

        var guid = 'xxxx-xxxx-xxxx-xxxx-xxxx'.replace(
            /[xy]/g,
            function (c) {
                var r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
            });

        return guid;
    }  

    ///////////////////////////////////////////////////////////////////////////
    // dynamic css styles
    //
    ///////////////////////////////////////////////////////////////////////////
    var css = [

        'canvas.graph {',
        'top:10px;',
        'left:30px;',
        'width:300px;',
        'height:300px;',
        'position:absolute;',
        'overflow:hidden;',
        '}',

        'div.chart-dropdown {',
        'position: absolute;',
        '}',

        '.scrollable-menu {',
        'height: auto;',
        'max-height: 300px;',
        'overflow-x: hidden;',
        'overflow-y: scroll;',
        '}',

    ].join('\n');

    $('<style type="text/css">' + css + '</style>').appendTo('head');

    return _self;
}